﻿module BulletLogic 
    
    open Microsoft.Xna.Framework
    open Microsoft.Xna.Framework.Input
    open Microsoft.Xna.Framework.Graphics
    open Utilities
    open Casanova
    open SI
    open Coroutines
    open System
    open System.IO;
    open System.Runtime.Serialization;
    open System.Runtime.Serialization.Formatters.Binary;
    open TypeMovement


    let mutable floorHeight= -4.0f
    let mutable time_life:float32<s> = 7.0f<s>
    let mutable playsound:bool = false;

    let mutable bullet_rotation:Matrix = Matrix.Identity
    let mutable matrixRotation:Matrix = Matrix.Identity
    let mutable camera_rotation:Matrix=Matrix.Identity

    let mutable direction:Vector3= new Vector3()
    let mutable bullet_position:Vector3 = new Vector3()
    let mutable camera_sideMove:Vector3=Vector3.Zero;

    let mutable modelBullet : Model = null
    let mutable modelBoss   : Model = null
    let mutable modelInvader: Model = null
    let mutable PlayerShipModel : Model = null
    let mutable modelBonus:Model = null

    let mutable ListPNGModel : System.Collections.Generic.List<Model> = new System.Collections.Generic.List<Model>()
    let mutable ListWeapons  : System.Collections.Generic.List<Model> = new System.Collections.Generic.List<Model>()
 
    let explosion_position_default = Vector3.One * -9999.0f
    let mutable explosion_position:Vector3 = explosion_position_default;

    let private points = 100
    let private total_MAX_number_of_enemies = 30
    let private total_MIN_number_of_enemies = 10

    let mutable private number_of_enemies:int = 0

    let mutable private percent_easy_enemy= 70
    let mutable private percent_normal_enemy= 20
    let mutable private percent_hard_enemy = 10

    let mutable private index_min=[|0;0;0|]

    let mutable private weaponSelect:int = 0

    let mutable private modelCollision: Model = null

    let private initialBossPosition = new Vector3(0.0f,30.0f,-150.0f)
       
    let mutable private start_to_follow_line =false

    let private ENEMY_LIFE,BOSS_LIFE,PLAYER_LIFE=1,10,10
    let private BULLET_BONUS,LASER_BONUS,MINE_BONUS=2.0f,1.5f,1.0f
    let private ENEMY_NORMAL_VALUE,ENEMY_HARD_VALUE,ENEMY_EASY_VALUE=2.5f,3.5f,1.5f

    type GameState = 
        {
            Enemies                 :   Variable<List<Enemy>>
            Projectiles             :   Variable<List<Projectile>>
            Boss                    :   Variable<Enemy>
            invokeBoss              :   Variable<bool>
            Player                  :   Variable<Player>
            mutable LevelCounter    :   int
            Score                   :   Variable<int>
  
        }
        member this.getLevel() = this.LevelCounter
    and Enemy =
         {
             Position                : Variable<Vector3>
             Velocity                : Variable<float32<m/s>>   
             mutable Life            : int
             mutable Movement        : float32
             myColor                 : Vector3
             Type                    : string
             Code                    : string
             Value                   : float32
         }

         member this.getPosition = (!this.Position)

    and Projectile =
            {
                Position            : Variable<Vector3>
                Velocity            : Variable<Vector3>         
                Time_of_Life        : Variable<float32<s>>
                Rotation            : Variable<Matrix>
                Enemy_Code          : string
                mutable Alive       : bool
                owner               : string
                myColor             : Vector3
                Type                : int
                Bonus               : float32
            }
    and Player = 
            {
                Position        : Variable<Vector3>
                mutable Life    : int

            }
    

    let mutable theEnemy:Enemy List =[]

    let createEnemies num_enemies=
                [
                    
                    let difficult_enemie = [
                                                ((int)((num_enemies-1) * percent_easy_enemy) / 100 )+ 1;
                                                ((int)((num_enemies-1) * percent_normal_enemy) / 100 )+ 1;
                                                ((int)((num_enemies-1) * percent_hard_enemy) / 100 )+ 1
                                            ]
                    
                    for i=0 to 2 do
                 
                        for j = 0 to difficult_enemie.Item(i)-1 do

                             let x = random_lerp -80.0f 80.0f
                             let y = random_lerp 15.0f 35.0f
                             let position = new Vector3(x,y, 5.0f*(float32)i+150.0f )
                             
                             let code = ((int)(random_lerp 1.0f 10000.0f)).ToString() + ((char)((int)(random_lerp 65.0f 123.0f))).ToString() + ((char)((int)(random_lerp 66.0f 122.0f))).ToString()
                             
                             
                             
                             
                             let mutable color =  
                                                    match i with
                                                    | 0 ->  Color.Green.ToVector3() 
                                                    | 1 -> Color.Orange.ToVector3()
                                                    |_  -> Color.Red.ToVector3() 
                             let mutable myType =  
                                                    match i with
                                                    | 0 ->  "easy" 
                                                    | 1 -> "normal"
                                                    |_  -> "hard" 

                             let v = 
                                        match i with
                                                    | 0 ->  (random_lerp -7.0f<m/s> -2.5f<m/s>) 
                                                    | 1 -> (random_lerp -4.0f<m/s> -2.5f<m/s>)
                                                    |_  -> (random_lerp -4.0f<m/s> -2.5f<m/s>)
                             
                             let points =  match myType with
                                                    |   "normal"    ->  ENEMY_NORMAL_VALUE
                                                    |   "hard"      ->  ENEMY_HARD_VALUE
                                                    |   _           ->  ENEMY_EASY_VALUE
                           
                             yield
                                    {
                                        Enemy.Position = variable(position)
                                        Velocity = variable(v)
                                        Movement = 0.0f
                                        myColor= color
                                        Type = myType
                                        Life = ENEMY_LIFE
                                        Code = code
                                        Value = points
                                    }

                ]

    let init_state(level:int,score:int) =
        {
            Projectiles = Variable(fun () -> [])

            Boss = Variable( fun ()-> {
                                           Enemy.Position = variable(initialBossPosition)
                                           Velocity = variable(1.0f<m/s>)
                                           Movement = 0.0f
                                           myColor= Color.Yellow.ToVector3()
                                           Type = "Boss"
                                           Life = BOSS_LIFE
                                           Code = "0A"
                                           Value = 10.0f
                                        }
                         )
            
            Enemies = Variable(fun () -> createEnemies number_of_enemies)

            invokeBoss = variable(false)

            Player = Variable (fun () -> {
                                            Player.Position = variable(Vector3(0.0f,floorHeight+0.5f,-80.0f))
                                            Life = PLAYER_LIFE
                                            
                                         }
                              )
            LevelCounter = level + 1

            Score = variable(score)
        }

    
    let mutable projectiles_enemies_State =  number_of_enemies <- 10
                                             init_state(0,0)
    
    let reset_variable()  =    start_to_follow_line <- false                                      
    let reset_state(level:int) =
        
        if(level < 0) then
            projectiles_enemies_State <- init_state(0,0)
            
        else
            number_of_enemies <- number_of_enemies + ((int)total_MAX_number_of_enemies-10)/total_MIN_number_of_enemies
            projectiles_enemies_State <- init_state(projectiles_enemies_State.LevelCounter,!projectiles_enemies_State.Score)

        
        reset_variable() 
           
    let whoIsEnemy() =  if( !projectiles_enemies_State.invokeBoss ) then
                            !projectiles_enemies_State.Boss::[]
                        else
                            !projectiles_enemies_State.Enemies
    


    let check_Collision() = 
                            for b in !projectiles_enemies_State.Projectiles do

                            match b.owner with
                                    | "player" ->       for enemy in theEnemy do


                                                        if ( b.Alive && Vector3.Distance( (!b.Position) , (!enemy.Position) ) < 10.0f ) then
                                           
                             
                                                            for mesh in modelCollision.Meshes do

                                                            let mutable bossBS = mesh.BoundingSphere
                                                            bossBS.Radius <-  2.0f
                                                            bossBS.Center <-  bossBS.Center + enemy.Position.Value

                                
                                                            for mesh1 in ListWeapons.Item(b.Type).Meshes do
                                    
                                                                  let mutable bulletBS = mesh1.BoundingSphere
                                                                  if(b.Type = 2) then
                                                                    bulletBS.Radius <-  2.0f
                                                                  else
                                                                    bulletBS.Radius <-  1.0f

                                                                  bulletBS.Center <-  bulletBS.Center + b.Position.Value

                                                                  if( b.Alive && bossBS.Intersects(bulletBS) ) then

                                                                        enemy.Life <- enemy.Life - 1
                                                                        explosion_position <- bulletBS.Center
                                                                        if (enemy.Life <=0 ) then
                                                                            projectiles_enemies_State.Score := !projectiles_enemies_State.Score + (int)(b.Bonus * enemy.Value)
                                                                        b.Alive<- false

                                                                        
                                                                        


                                    | _ ->           
                                                    if ( b.Alive && Vector3.Distance( (!b.Position) , (!projectiles_enemies_State.Player.Value.Position) ) < 10.0f  ) then
                                           
                                                              for mesh in PlayerShipModel.Meshes do

                                                                let mutable shipBS = mesh.BoundingSphere
                                                                shipBS.Radius <-  3.0f
                                                                shipBS.Center <-  shipBS.Center + projectiles_enemies_State.Player.Value.Position.Value - new Vector3(0.0f,7.0f,0.0f)

                                
                                                                for mesh1 in ListWeapons.Item(b.Type).Meshes do
                                    
                                                                      let mutable bulletBS = mesh1.BoundingSphere
                                                                      bulletBS.Radius <-  3.0f
                                                                      bulletBS.Center <-  bulletBS.Center + b.Position.Value

                                                                      if( b.Alive && shipBS.Intersects(bulletBS)  ) then
                                    
                                                                            projectiles_enemies_State.Player.Value.Life <- projectiles_enemies_State.Player.Value.Life - 1 
                                                                            do System.Console.WriteLine(" NAVICELLA COLPITA!! life: "+projectiles_enemies_State.Player.Value.Life.ToString())
                                                                            b.Alive <- false



    let NR_POINTS_IN_SPACE = 2000
    let points_in_space =[|Vector3.Zero;Vector3(0.0f,30.0f,89.0f);Vector3(145.0f,30.0f,89.0f);Vector3(0.0f,80.0f,90.0f);Vector3(-150.0f,30.0f,90.0f);Vector3(0.0f,30.0f,90.0f);Vector3.Zero|]
    let line = createCRSplineCurve(points_in_space )( NR_POINTS_IN_SPACE )
    


    let rec update_state(dt:float32<s>) =

            

            if((!projectiles_enemies_State.Boss).Life <= 0) then
                reset_state(1)
            
            for enemy in !projectiles_enemies_State.Enemies do 
                 update_enemy enemy dt
                 enemy.Movement <- enemy.Movement + (50.0f * -1.0f<m/s> / enemy.Velocity.Value )*(dt/1.0f<s>) 
   
            projectiles_enemies_State.Enemies :=
            [              
                for e in !projectiles_enemies_State.Enemies do
                    if( e.Life > 0) then
                      yield e
                    

            ]

            
            
            if( projectiles_enemies_State.Enemies.Value.Length = 0 && !projectiles_enemies_State.invokeBoss = false ) then

                    (projectiles_enemies_State.invokeBoss) := true
                    modelCollision <- ListPNGModel.Item(1)
   
             else
                    if( !projectiles_enemies_State.invokeBoss ) then
                        
                        if (modelCollision = null ) then            // Accade quando carico la prtita e sono sdubito contro il boss
                            modelCollision <- ListPNGModel.Item(1)

                        (projectiles_enemies_State.invokeBoss) := true

                        if( projectiles_enemies_State.Boss.Value.Life > 0 ) then

                            let boss = !projectiles_enemies_State.Boss                  
                            update_enemy boss dt
                        
                        projectiles_enemies_State.Boss := projectiles_enemies_State.Boss.Value
                    else
                        modelCollision <- ListPNGModel.Item(0)

            for bullet in !projectiles_enemies_State.Projectiles do 
                 update_projectile bullet dt

            projectiles_enemies_State.Projectiles :=
            [   
                for b in projectiles_enemies_State.Projectiles.Value do

                    if( b.Alive ) then
                        yield b
            ]

            theEnemy <- whoIsEnemy()

            projectiles_enemies_State.Score := !projectiles_enemies_State.Score

            check_Collision()

           

            (!projectiles_enemies_State.Player).Position:=!(!projectiles_enemies_State.Player).Position
            projectiles_enemies_State.Player := projectiles_enemies_State.Player.Value
            

    and private update_projectile (bullet:Projectile) (dt:float32<s>) =
    
            let mutable velocity = Vector3.Zero

            match bullet.Type with
            | 0 | 1 ->
                    if( (!bullet.Position).Y-0.3f < floorHeight ) then
                        
                        if( bullet.Type = 0 )then
                            velocity <- !bullet.Velocity * new Vector3(1.0f,-1.0f,1.0f)
                        else
                            bullet.Alive <- false
                    else
                        
                        velocity <- !bullet.Velocity
                
                    let next_position= !bullet.Position + velocity*(dt/1.0f<s>) 

                    bullet.Position := next_position
                    bullet.Velocity := velocity
                    bullet.Rotation := !bullet.Rotation

                    if( (!bullet.Time_of_Life) > time_life) then
                        bullet.Alive <- false
                    else
                        bullet.Time_of_Life := !bullet.Time_of_Life + dt

            
            | _ -> //*     INSEGUIMENTO  MINE       *//
                    
                    velocity <- !bullet.Velocity

                    let next_position= !bullet.Position + velocity*(dt/1.0f<s>) * 3.0f
                    
                    let mutable enemy_pos:Vector3 = Vector3.Zero
                    let mutable find = false

                    for e in theEnemy do
                        if(not(find)) then
                            if(bullet.Enemy_Code.Equals( e.Code ) )then
                                enemy_pos <- e.Position.Value
                                find <- true
            
            
                    bullet.Position := next_position
                    
                    let a = modelCollision.Meshes.[0].BoundingSphere.Center

                    bullet.Velocity :=  ( ( enemy_pos - ( Vector3(-2.0f,2.0f,2.0f) ))  - next_position)*1.5f // Vector3(-2.0f,2.0f,2.0f) in modo da colpire dal davanti i nemici 

                    do System.Console.WriteLine("code: "+bullet.Enemy_Code.ToString())

                    if( (!bullet.Time_of_Life) > time_life) then
                        bullet.Alive <- false
                    else
                        bullet.Time_of_Life := !bullet.Time_of_Life + dt


   
    and private update_enemy (enemy:Enemy) (dt:float32<s>) =
        

         if( (!enemy.Position).Z < -90.0f && enemy.Type.Equals("Boss") = false ) then

                    let next_position = new Vector3((!enemy.Position).X,(!enemy.Position).Y,150.0f)
                    enemy.Position := next_position
                  
              
         else
                                
               match enemy.Type with
                 |"easy" ->    let next_position = new Vector3((!enemy.Position).X,(!enemy.Position).Y ,(!enemy.Position).Z+enemy.Velocity.Value*dt/1.0f<m>)
                               enemy.Position := next_position
                               enemy.Velocity := enemy.Velocity.Value

                 |"normal"->   let next_position = new Vector3((!enemy.Position).X + circonferenzaState.xCos.Item((int)enemy.Movement%points),(!enemy.Position).Y+circonferenzaState.ySin.Item((int)enemy.Movement%points),(!enemy.Position).Z+enemy.Velocity.Value*dt/1.0f<m>)
                               enemy.Position := next_position
                               enemy.Velocity := enemy.Velocity.Value
                 |"hard" ->    let next_position = new Vector3((!enemy.Position).X+RodoneaState.xCos.Item((int)enemy.Movement%points),(!enemy.Position).Y + RodoneaState.ySin.Item((int)enemy.Movement%points),(!enemy.Position).Z+enemy.Velocity.Value*dt/1.0f<m>)
                               enemy.Position := next_position
                               enemy.Velocity := enemy.Velocity.Value
                 |"Boss" ->    

                               if(start_to_follow_line) then
                                   let next_position = line.[(int)enemy.Movement%NR_POINTS_IN_SPACE+1]
                                   enemy.Position := next_position
                                   enemy.Movement <- enemy.Movement + (enemy.Velocity.Value * (1.0f<s>/1.0f<m>) )//(dt/1.0f<s>)
                               else
                                   let next_position = new Vector3( (!enemy.Position).X  ,(!enemy.Position).Y , lerp (dt/1.0f<s>) 95.0f enemy.Position.Value.Z )
                                   enemy.Position := next_position
                                   if(next_position.Z>89.0f)then
                                     start_to_follow_line <- true
                                
                               enemy.Velocity := enemy.Velocity.Value
                               

                 |_      ->    do System.Console.WriteLine("nessuno dei 4")


    let private (!) = immediate_read
    let private (:=) = immediate_write 

    let mutable player_acceleration=0.2f 

    type MyClassWithCLIEvent() =

        let _shoot = new Event<_>()
        let _shoot2 = new Event<_>()
        let _moveRight = new Event<_>()
        let _moveLeft = new Event<_>()
        let _moveUp = new Event<_>()
        let _moveDown = new Event<_>()
        let _moveForward = new Event<_>()
        let _moveBackward = new Event<_>()
        let _accelerate = new Event<_>()

        [<CLIEvent>]
        member this.Shoot = _shoot.Publish

        member this._iShoot(owner,color,typeWeapon) =
            _shoot.Trigger(this, owner , color, typeWeapon)
        
        
        member this.Right = _moveRight.Publish
        member this._iMoveRight(intensity:Vector2) =  _moveRight.Trigger(this,intensity)

        member this.Left = _moveLeft.Publish
        member this._iMoveLeft() =  _moveLeft.Trigger(this)

        member this.Up = _moveUp.Publish
        member this._iMoveUp(intensity:float32) =  _moveUp.Trigger(this,intensity)

        member this.Down = _moveDown.Publish
        member this._iMoveDown(intensity:float32) =   _moveDown.Trigger(this,intensity)

        member this.Backward = _moveBackward.Publish
        member this._iMoveBackward() = _moveBackward.Trigger(this)

        member this.Forward = _moveForward.Publish
        member this._iMoveForward(intensity:Vector2) = _moveForward.Trigger(this,intensity)

        member this.Accelerate = _accelerate.Publish
        member this._iAccelerate() = _accelerate.Trigger(this)


    let Event = new MyClassWithCLIEvent()



    Event.Shoot.Add( fun (sender,owner,color,typeWeapon) -> 
                                                //let mutable typeWeapon = 0
                                                
                                                //if( owner.Equals("player") ) then
                                                  //  typeWeapon <- weaponSelect
                                                
                                                match typeWeapon with
                                                | 1 -> //LASER
                                                        
                                                        for i = 1 to 2 do
                                                            let v = [|!(!projectiles_enemies_State.Player).Position + new Vector3(2.5f, 6.5f, 3.5f) ; !(!projectiles_enemies_State.Player).Position + new Vector3(-2.5f, 6.5f, 3.5f)|]
                                                            projectiles_enemies_State.Projectiles := 
                                                            {
                                                                Projectile.Position = variable(v.[i-1])
                                                                Velocity = variable(direction)
                                                                Alive    =  true
                                                                Time_of_Life = variable(0.0f<s>)
                                                                Rotation = variable(bullet_rotation)
                                                                owner    = owner
                                                                myColor  = color
                                                                Type = typeWeapon
                                                                Enemy_Code = ""
                                                                Bonus=LASER_BONUS
                                                             } :: !projectiles_enemies_State.Projectiles
                                                
                                                | 2 -> //MINE
                                                        
                                                        let rp = [|!(!projectiles_enemies_State.Player).Position + Vector3(0.0f,7.0f,0.0f) ;
                                                                !(!projectiles_enemies_State.Player).Position + Vector3(8.0f,3.0f,0.0f);
                                                                !(!projectiles_enemies_State.Player).Position - Vector3(8.0f,-3.0f,0.0f)|]
                                                        
                                                        let mutable d = [|
                                                                                        for e in theEnemy do
                                                                                          yield (  Vector3.Distance( !e.Position, !projectiles_enemies_State.Player.Value.Position) )
                                                                        |]
                                                        
                                                       
                                                        let mutable threeMin:Vector3[]  = [| Vector3.Zero  ; Vector3.Zero ; Vector3.Zero |]
                                                        let mutable distmin= 9999.0f
                                                        
                                                        let maxBullet = MathHelper.Clamp(theEnemy.Length |> float32,1.0f,3.0f) |>int

                                                        for i=1 to maxBullet do

                                                            let mutable cont=0
                                                            index_min.[i-1] <- 0
                                                            distmin <- 9999.0f

                                                            for j=1 to d.Length do
                                                                    if( distmin > d.[j-1] ) then
                                                                        threeMin.[i-1] <-  (theEnemy.Item(j-1)).Position.Value
                                                                        distmin <- d.[j-1]
                                                                        index_min.[i-1]<-cont
                                                                        cont <- cont + 1
                                                                    else
                                                                        cont <- cont + 1

                                                            d.[index_min.[i-1]] <- 9999.0f


                                                        let position = projectiles_enemies_State.Player.Value.Position.Value
                                                        
                                                       

                                                        for i = 1 to maxBullet do
                                                            
                                                            let code = theEnemy.Item(index_min.[i-1]).Code
                                                            let v=rp.[i-1]     
                                                            projectiles_enemies_State.Projectiles := 
                                                            {
                                                                Projectile.Position = variable(v)
                                                                Velocity = variable(position - threeMin.[i-1])
                                                                Alive    =  true
                                                                Time_of_Life = variable(0.0f<s>)
                                                                Rotation = variable(bullet_rotation)
                                                                owner    = owner
                                                                myColor  = color
                                                                Type = typeWeapon
                                                                Enemy_Code = code
                                                                Bonus= MINE_BONUS
                                                             } :: !projectiles_enemies_State.Projectiles
                                                
                                                | _ -> //BULLET
                                                           
                                                            projectiles_enemies_State.Projectiles := 
                                                                {
                                                                    Projectile.Position = variable(bullet_position)
                                                                    Velocity = variable(direction)
                                                                    Alive    =  true
                                                                    Time_of_Life = variable(0.0f<s>)
                                                                    Rotation = variable(bullet_rotation)
                                                                    owner    = owner
                                                                    myColor  = color
                                                                    Type = typeWeapon
                                                                    Enemy_Code = ""
                                                                    Bonus=BULLET_BONUS
                                                                 } :: !projectiles_enemies_State.Projectiles

                                                
                            )

                            
    Event.Right.Add( fun (sender,intensity) ->   
                            let x =  MathHelper.Clamp( (!(!projectiles_enemies_State.Player).Position).X + camera_sideMove.X * player_acceleration * intensity.X , -125.0f,125.0f)
                            (!projectiles_enemies_State.Player).Position := Vector3(x,(!(!projectiles_enemies_State.Player).Position).Y,(!(!projectiles_enemies_State.Player).Position).Z)  
                           
                                            )


    Event.Left.Add( fun (sender) -> Event._iMoveRight( Vector2.One * -1.0f ) )

    Event.Up.Add( fun (sender,intensity) ->   
                            let y =  MathHelper.Clamp( (!(!projectiles_enemies_State.Player).Position).Y  +  player_acceleration * intensity, floorHeight + 0.5f ,30.0f)
                            (!projectiles_enemies_State.Player).Position := Vector3((!(!projectiles_enemies_State.Player).Position).X,y,(!(!projectiles_enemies_State.Player).Position).Z)   
                            )

    Event.Down.Add( fun (sender,intensity) ->    
                           Event._iMoveUp(-intensity)
                   )


    Event.Forward.Add( fun (sender,intensity) ->     
                            let z =  MathHelper.Clamp( (!(!projectiles_enemies_State.Player).Position).Z - camera_rotation.Forward.Z * player_acceleration * intensity.Y , -150.0f,-60.0f)
                            (!projectiles_enemies_State.Player).Position := Vector3((!(!projectiles_enemies_State.Player).Position).X,(!(!projectiles_enemies_State.Player).Position).Y,z)  
                                                        
                    )
    
    Event.Backward.Add( fun (sender) ->  Event._iMoveForward( Vector2.One * -1.0f ) )

    Event.Accelerate.Add( fun (sender) -> player_acceleration <- 0.6f )

    let mutable useJoystick = false;

    let private main() =

        let enemy_shoot() =
            co{
                do! wait 1.0

                let l = (!projectiles_enemies_State.Enemies).Length 
                if (l > 0) then

                    let r = random.Next(0,l)
                    let enemyShoot = projectiles_enemies_State.Enemies.Value.Item( r ).Position.Value
                    direction <- (!(!projectiles_enemies_State.Player).Position)+Vector3(0.0f,5.0f,0.0f) - enemyShoot
                    bullet_position <- enemyShoot
                    
                    Event._iShoot("enemy",projectiles_enemies_State.Enemies.Value.Item( r ).myColor,0)
                
                return()                                       

            } 
        let  move_boss() =
            co{
                
                do! yield_

                
                if( projectiles_enemies_State.Boss.Value.Life < 5) then
                    projectiles_enemies_State.Boss.Value.Velocity:= 2.0f<m/s>
                else
                    projectiles_enemies_State.Boss.Value.Velocity := 1.0f<m/s>

                return()

            }
        let  boss_shoot() = 
            co{   
                let r=random_lerp 0.5f 2.0f|>float
                do! wait r
                if( projectiles_enemies_State.invokeBoss.Value && projectiles_enemies_State.Boss.Value.Life > 0) then
                            
                            let enemyShoot = projectiles_enemies_State.Boss.Value.Position.Value
                            direction <- !(!projectiles_enemies_State.Player).Position - enemyShoot
                            bullet_position <- enemyShoot
                            Event._iShoot("Boss",Color.Blue.ToVector3(),0)

                return()
            }

        (  repeat_ (enemy_shoot()) .||> repeat_ (move_boss()) .||> repeat_ (boss_shoot())  )
        
    
    let mutable shooting:bool = false

    let private main_player() =
        let mine()=
            co{
                do! yield_
                if(weaponSelect = 2 && shooting) then
                    playsound <- true
                    Event._iShoot("player",Color.WhiteSmoke.ToVector3(),weaponSelect)
                    do! wait 0.8
                    playsound <- false
                    do! wait 1.0
                
                return()
            }
        let laser()=
            co{
                do! yield_
                if(weaponSelect = 1 && shooting) then
                    playsound <- true
                    Event._iShoot("player",Color.WhiteSmoke.ToVector3(),weaponSelect)
                    
                    do! wait 0.5
                    playsound <- false
                

                return()
            }

        let bullet()=
            co{
                do! yield_
                if(weaponSelect = 0 && shooting ) then
                    playsound <- true
                    Event._iShoot("player",Color.WhiteSmoke.ToVector3(),weaponSelect)
                    
                    do! wait 0.8
                    playsound <- false
                

                return()
            }

        let KeyboardInput()=
            
                        if (Keyboard.GetState().[Keys.W] = KeyState.Down ) then 
                               Event._iMoveForward(Vector2.One)

                        if (Keyboard.GetState().[Keys.S] = KeyState.Down ) then
                               Event._iMoveBackward()

                        if (Keyboard.GetState().[Keys.A] = KeyState.Down ) then 
                                Event._iMoveLeft()

                        if (Keyboard.GetState().[Keys.D] = KeyState.Down ) then                
                                Event._iMoveRight(Vector2.One)

                        if (Keyboard.GetState().[Keys.Space] = KeyState.Down ) then
                                Event._iMoveUp(1.0f)

                        if (Keyboard.GetState().[Keys.LeftControl] = KeyState.Down ) then
                                Event._iMoveDown(1.0f)


                        if (Keyboard.GetState().[Keys.LeftShift] = KeyState.Down  && player_acceleration <> 0.6f) then
                                Event._iAccelerate()
                        
                        if( Mouse.GetState().LeftButton = ButtonState.Pressed ) then
                            shooting <-  true
                        else
                            shooting <-  false

                        if (Keyboard.GetState().[Keys.D1] = KeyState.Down ) then 
                            weaponSelect <- 0
                        if (Keyboard.GetState().[Keys.D2] = KeyState.Down ) then 
                            weaponSelect <- 1
                        if (Keyboard.GetState().[Keys.D3] = KeyState.Down ) then 
                            weaponSelect <- 2


        let GamepadInput()=
                        
                        
                        Event._iMoveForward( GamePad.GetState(PlayerIndex.One).ThumbSticks.Left );
                        Event._iMoveRight( GamePad.GetState(PlayerIndex.One).ThumbSticks.Left )
                        Event._iMoveUp( GamePad.GetState(PlayerIndex.One).Triggers.Right)
                        Event._iMoveDown( GamePad.GetState(PlayerIndex.One).Triggers.Left)

                        if (GamePad.GetState(PlayerIndex.One).Buttons.LeftStick = ButtonState.Pressed ) then
                                Event._iAccelerate()

                        if( GamePad.GetState(PlayerIndex.One).Buttons.RightShoulder = ButtonState.Pressed ) then
                            shooting <-   true
                        else
                            shooting <-   false
                        
                        if (GamePad.GetState(PlayerIndex.One).Buttons.X = ButtonState.Pressed ) then 
                            weaponSelect <- 0
                        if (GamePad.GetState(PlayerIndex.One).Buttons.A = ButtonState.Pressed ) then 
                            weaponSelect <- 1
                        if (GamePad.GetState(PlayerIndex.One).Buttons.B = ButtonState.Pressed ) then 
                            weaponSelect <- 2

        let booster() =
            co{
                    do! yield_
                    if( player_acceleration > 0.2f ) then
                        do! wait 5.0
                        player_acceleration <- 0.2f
                    return()
                        
            }
        let move_ship() =
             co{    
                        do! yield_

                        (!projectiles_enemies_State.Player).Position := !(!projectiles_enemies_State.Player).Position

                        if( useJoystick && GamePad.GetState(PlayerIndex.One).IsConnected ) then
                            GamepadInput()
                        else
                            KeyboardInput()

                        return()          
             }

       
        
            


        ( repeat_ (bullet()) .||> repeat_ (laser()) .||> repeat_ (mine()) .||> repeat_ (move_ship()) .||> repeat_ (booster())  )
       
    let mutable m2=main_player()
    let mutable m=main()
    let update_script() = 
        m <- update_ai m
        m2<- update_ai m2






    (*      missili che ruotano non funzionante
    
                    //next_position.Normalize()
                   // enemy_pos.Normalize()
                   (*
                    matrixRotation <- Matrix.CreateLookAt(bullet.Position.Value,(enemy_pos - next_position),Vector3.Backward)
                    
                    let mutable s=ref Vector3.Zero
                    let mutable rot=ref Quaternion.Identity
                    let mutable t=ref Vector3.Zero
                    let r= matrixRotation.Decompose(s,rot,t)
                    

                    let rota = Matrix.CreateLookAt(bullet.Position.Value,Vector3.Normalize(enemy_pos - next_position),Vector3.Up)
                     
                    bullet.Rotation := Matrix.CreateFromQuaternion( Quaternion.Slerp( Quaternion.CreateFromRotationMatrix(bullet.Rotation.Value),Quaternion.CreateFromRotationMatrix(rota),0.01f ) )
                    
                    //bullet.Rotation := matrixRotation
                    //bullet.Rotation := Matrix.CreateFromQuaternion(Quaternion.Normalize(rot.Value))

                    let cosTheta= Vector3.Dot(next_position,enemy_pos) 

                    let Theta = System.Math.Acos((float)cosTheta)
                    *)
    
    *)